// Copyright (c) 2010 Manuel Peinado Gallego <manuel.peinado@gmail.com>
// Distributed under the MIT license

#include "stdafx.h"
#include "WorldBuilder.h"
#include "TextureManager.h"


TextureManager::TextureManager()
: m_initialized(false)
{
}

void TextureManager::addDefaultTexture()
{
    if(!m_initialized)
    {
        m_initialized = true;
        registerTexture(getDefaultTexture()->getRef<Texture>());
    }
}

void TextureManager::registerTexture(ref<Texture> tex)
{
    // A dirty workaround for the fact that SOIL cannot be used from a
    // static constructor, due to the well known static initialization fiasco
    addDefaultTexture();

    // If a Texture by that name exists, don't do anything
    if(getTextureByName(tex->getName()) != NULL)
    {
        ASSERT(false);
        return;
    }

    // If a Texture by that name exists, don't do anything
    if(getTextureById(tex->getId()) != NULL)
    {
        ASSERT(false);
        return;
    }

    tex->setManager(this);
    m_textures.insert(tex);
    
    ListenerIt it = m_listeners.begin();
    for(; it != m_listeners.end(); ++it)
    {
        TextureListener* listener = *it;
        listener->onTextureAddedOrRemoved(this, tex.get());
    }
}


std::wstring TextureManager::generateNameFromPrefix(
    const std::wstring& prefix) const
{
    for(int i = 0; ; ++i) // Will eventually find an unused name
    {
        std::wostringstream oss;
        oss << prefix << i;
        if(getTextureByName(oss.str()) == NULL)
        {
            return oss.str();
        }
    }
}

Texture* TextureManager::getTextureById(size_t id) const
{
    // TODO this map should be the other way around for efficiency
    typedef TextureSet::const_iterator It;
    for(It it = m_textures.begin(); it != m_textures.end(); ++it)
    {
        if((*it)->getId() == id)
        {
            return it->get();
        }
    }
    return NULL;
}

Texture* TextureManager::getTextureByName(const std::wstring& name) const
{
    // TODO this map should be the other way around for efficiency
    typedef TextureSet::const_iterator It;
    for(It it = m_textures.begin(); it != m_textures.end(); ++it)
    {
        if((*it)->getName() == name)
        {
            return it->get();
        }
    }
    return NULL;
}

// - - -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 

void TextureManager::clear()
{
    m_textures.clear();
    addDefaultTexture();
}

// - - -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 

ref<Texture> TextureManager::getDefaultTexture()
{
    static ref<Texture> theInstance;
    if(theInstance == NULL)
    {
        theInstance.reset(new Texture("checker.png"));
        theInstance->setName(L"default");
    }
    return theInstance;
}

// - - -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 

TextureManager::TextureIt TextureManager::beginTextures()
{
    // A dirty workaround for the fact that SOIL cannot be used from a
    // static constructor, due to the well known static initialization fiasco
    addDefaultTexture();

    return m_textures.begin();
}

TextureManager::TextureIt TextureManager::endTextures()
{
    return m_textures.end();
}


size_t TextureManager::getTextureCount() const
{
    return m_textures.size();
}

// - - -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 

void TextureManager::addTextureListener(TextureListener* listener)
{
    ASSERT(m_listeners.find(listener) == m_listeners.end());
    m_listeners.insert(listener);
}

void TextureManager::removeTextureListener(TextureListener* listener)
{
    ASSERT(m_listeners.find(listener) != m_listeners.end());
    m_listeners.erase(listener);
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

ref<Texture> TextureManager::simpleLoad(const std::string& fileName, 
                                        const char* fileExt)
{
    ref<Texture> tex(new Texture(fileName + fileExt));
    CA2T unicode(fileName.c_str());
    tex->setName(generateNameFromPrefix(std::wstring(unicode)));
    registerTexture(tex);
    return tex;
}

ref<Texture> TextureManager::simplePngLoad(const std::string& fileName)
{
    return simpleLoad(fileName, ".png");
}

ref<Texture> TextureManager::simpleJpgLoad(const std::string& fileName)
{
    return simpleLoad(fileName, ".jpg");
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
//void TextureManager::notifyTextureAppearanceChanged(Texture* mat)
//{
//    ListenerIt it = m_listeners.begin();
//    for(; it != m_listeners.end(); ++it)
//    {
//        TextureListener* listener = *it;
//        listener->onTextureAppearanceChanged(this, mat);
//    }
//}
